'use strict'

const path = require('path')
const fse = require('fs-extra')
const pkgDir = require('pkg-dir').sync // promise.sync
const pathExists = require('path-exists').sync
const npminstall = require('npminstall')

const { isObject, formatPath } = require('@lenovo-cli/utils')
const { fetchLatestVersion } = require('@lenovo-cli/fetch-pkg-info')

class Package {
  constructor(opts) {
    this.validate(opts)
    this.targetPath = opts.targetPath // package的目标路径
    this.storeDir = opts.storeDir // package的缓存路径
    this.packageName = opts.packageName
    this.packageVersion = opts.packageVersion
    this.cacheFilePathPrefix = this.packageName.replace('/', '_') // package的缓存目录前缀
  }
  validate(opts) {
    if (!opts) {
      throw new Error('Package类的options参数不能为空!')
    }
    if (!isObject(opts)) {
      throw new Error('Package类的options参数必须为对象！')
    }
  }
  async prepare() {
    // 缓存路径存在，缓存目录不存在时，创建目录
    if (this.storeDir && !pathExists(this.storeDir)) {
      fse.mkdirpSync(this.storeDir)
    }
    if (this.packageVersion === 'latest') {
      this.packageVersion = await fetchLatestVersion(this.packageName)
    }
  }
  get cacheFilePath() {
    return path.resolve(
      this.storeDir,
      `_${this.cacheFilePathPrefix}@${this.packageVersion}@${this.packageName}`
    )
  }
  getSpecificCacheFilePath(packageVersion) {
    return path.resolve(
      this.storeDir,
      `_${this.cacheFilePathPrefix}@${packageVersion}@${this.packageName}`
    )
  }
  // 判断package是否存在
  async exists() {
    if (this.storeDir) {
      await this.prepare()
      return pathExists(this.cacheFilePath)
    } else {
      return pathExists(this.targetPath)
    }
  }
  // package 安装
  async install() {
    await this.prepare()
    return npminstall({
      root: this.targetPath,
      storeDir: this.storeDir,
      registry: 'http://registry.npmjs.org',
      pkgs: [{ name: this.packageName, version: this.packageVersion }],
    })
  }
  // 更新
  async update() {
    await this.prepare()
    // 获取最新的npm版本号
    const latestPackageVersion = await fetchLatestVersion(this.packageName)
    // 查询最新版本号对应的路径是否存在
    const lastestFilePath = this.getSpecificCacheFilePath(latestPackageVersion)
    // 如果不存在，则直接安装最新版本
    if (!pathExists(lastestFilePath)) {
      await npminstall({
        root: this.targetPath,
        storeDir: this.storeDir,
        registry: 'http://registry.npmjs.org',
        pkgs: [{ name: this.packageName, version: latestPackageVersion }],
      })
    }
    this.packageVersion = latestPackageVersion
  }

  // 获取包入口文件的路径
  getRootFilePath() {
    function _getRootFile(targetPath) {
      // 获取package.json所在目录 - 通过库pkg-dir
      const dir = pkgDir(targetPath)
      if (dir) {
        // 读取package.json - require()
        const pkgFile = require(path.resolve(dir, 'package.json'))
        // 找 main/lib 下的path
        if (pkgFile && pkgFile.main) {
          // 路径兼容！！！（mac / windows）
          return formatPath(path.resolve(dir, pkgFile.main))
        }
      }
      return null
    }

    if (this.storeDir) {
      return _getRootFile(this.cacheFilePath)
    } else {
      return _getRootFile(this.targetPath)
    }
  }
}
module.exports = Package
